package com.canaan.business.service.inOutStock.impl;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;
import java.util.stream.Collectors;

import cn.hutool.core.util.StrUtil;
import com.canaan.business.common.enums.agv.AgvEnum;
import com.canaan.business.common.enums.inOutStock.BindTypeEnum;
import com.canaan.business.common.enums.inOutStock.InOrderStatusEnum;
import com.canaan.business.common.enums.inOutStock.InOutStockTypeEnum;
import com.canaan.business.common.enums.storehouse.InOutStorageOperationEnum;
import com.canaan.business.common.enums.storehouse.StoreHouseLocationTypeEnum;
import com.canaan.business.common.enums.storehouse.StoreHouseTypeEnum;
import com.canaan.business.common.enums.storehouse.StorehouseStockStatusEnum;
import com.canaan.business.common.helper.BeanHelper;
import com.canaan.business.common.helper.EmptyStockHelper;
import com.canaan.business.domain.basic.StockStrategy;
import com.canaan.business.domain.basic.WmsStorehouse;
import com.canaan.business.domain.basic.WmsStorehouseArea;
import com.canaan.business.domain.basic.WmsStorehouseLocation;
import com.canaan.business.domain.bill.Tray;
import com.canaan.business.domain.bill.TrayDetail;
import com.canaan.business.domain.inOutStock.InStockBill;
import com.canaan.business.domain.inOutStock.InStockBillDetail;
import com.canaan.business.domain.storehouse.WmsStorehouseStock;
import com.canaan.business.domain.vo.InStockPutWayVo;
import com.canaan.business.domain.vo.WmsStorehouseStockVo;
import com.canaan.business.service.agv.IAgvTaskDispatchService;
import com.canaan.business.service.basic.IStockStrategyService;
import com.canaan.business.service.basic.IWmsStorehouseAreaService;
import com.canaan.business.service.basic.IWmsStorehouseLocationService;
import com.canaan.business.service.basic.IWmsStorehouseService;
import com.canaan.business.service.bill.ITrayDetailService;
import com.canaan.business.service.bill.ITrayService;
import com.canaan.business.service.inOutStock.*;
import com.canaan.business.service.storehouse.IStorehouseStockStrategyService;
import com.canaan.business.service.storehouse.IWmsStockInStockStrategyService;
import com.canaan.business.service.storehouse.IWmsStorehouseStockService;
import com.canaan.common.utils.DateUtils;
import com.canaan.common.utils.SecurityUtils;
import com.canaan.common.utils.StringUtils;
import com.canaan.common.utils.TableNoUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import com.canaan.business.mapper.inOutStock.BindRecordMapper;
import com.canaan.business.domain.inOutStock.BindRecord;
import org.springframework.transaction.annotation.Transactional;

/**
 * 绑定关系Service业务层处理
 *
 * @author canaan
 * @date 2025-03-29
 */
@Service
public class BindRecordServiceImpl implements IBindRecordService {
    protected final Logger logger = LoggerFactory.getLogger(this.getClass());
    @Resource
    private BindRecordMapper bindRecordMapper;

    @Resource
    private IWmsStorehouseLocationService locationService;
    @Resource
    private IWmsStorehouseAreaService areaService;
    @Resource
    private IWmsStorehouseService storehouseService;

    @Resource
    private IBindRecordService bindRecordService;
    @Resource
    private IWmsStorehouseStockService storehouseStockService;
    @Resource
    private ITrayService trayService;
    @Resource
    private ITrayDetailService trayDetailService;
    @Resource
    private IInStockBillService inStockBillService;
    @Resource
    private IInStockBillDetailService inStockBillDetailService;
    @Resource
    private IAdjustLocationBillService adjustLocationBillService;
    @Resource
    private IAdjustLocationBillDetailService adjustLocationBillDetailService;
    @Resource
    private IStorehouseStockStrategyService storehouseStockStrategyService;
    @Resource
    private IAgvTaskDispatchService agvTaskDispatchService;
    @Resource
    private IStockStrategyService stockStrategyService;
    @Resource
    private BeanHelper beanHelper;
    @Resource
    private EmptyStockHelper emptyStockHelper;
    /**
     * 查询绑定关系
     *
     * @param parentNo 绑定关系主键
     * @return 绑定关系
     */
    @Override
    public BindRecord selectBindRecordByParentNo(String parentNo) {
        return bindRecordMapper.selectBindRecordByParentNo(parentNo);
    }

    /**
     * 查询绑定关系列表
     *
     * @param bindRecord 绑定关系
     * @return 绑定关系
     */
    @Override
    public List<BindRecord> selectBindRecordList(BindRecord bindRecord) {
        return bindRecordMapper.selectBindRecordList(bindRecord);
    }

    /**
     * 新增绑定关系
     *
     * @param bindRecord 绑定关系
     * @return 结果
     */
    @Override
    public int insertBindRecord(BindRecord bindRecord) {
        bindRecord.setCreateBy(SecurityUtils.getUsername());
        bindRecord.setCreateTime(DateUtils.getNowDate());
        return bindRecordMapper.insertBindRecord(bindRecord);
    }

    /**
     * 批量新增绑定关系
     *
     * @param bindRecordList 绑定关系列表
     * @return 结果
     */
    @Override
    public int batchInsertBindRecord(List<BindRecord> bindRecordList) {
        String username = SecurityUtils.getUsername();
        Date currerTime = DateUtils.getNowDate();
        for (BindRecord bindRecord : bindRecordList){
            bindRecord.setCreateBy(username);
            bindRecord.setCreateTime(currerTime);
        }
        int insertNum = 0;
        for (int i=0; i<bindRecordList.size();) {
            int endIndex = i+500;
            if (endIndex > bindRecordList.size()) {
                endIndex = bindRecordList.size();
            }
            insertNum = insertNum + bindRecordMapper.batchInsertBindRecord(bindRecordList.subList(i, endIndex));
            i = endIndex;
        }
        return insertNum;
    }

    /**
     * 修改绑定关系
     *
     * @param bindRecord 绑定关系
     * @return 结果
     */
    @Override
    public int updateBindRecord(BindRecord bindRecord) {
        bindRecord.setUpdateBy(SecurityUtils.getUsername());
        bindRecord.setUpdateTime(DateUtils.getNowDate());
        return bindRecordMapper.updateBindRecord(bindRecord);
    }

    /**
     * 批量修改绑定关系
     *
     * @param bindRecordList 绑定关系列表
     * @return 结果
     */
    @Override
    public int batchUpdateBindRecord(List<BindRecord> bindRecordList) {
        String username = SecurityUtils.getUsername();
        Date currerTime = DateUtils.getNowDate();
        for (BindRecord bindRecord : bindRecordList){
            bindRecord.setUpdateBy(username);
            bindRecord.setUpdateTime(currerTime);
        }
        int updateNum = 0;
        for (int i=0; i<bindRecordList.size();) {
            int endIndex = i+500;
            if (endIndex > bindRecordList.size()) {
                endIndex = bindRecordList.size();
            }
            updateNum = updateNum + bindRecordMapper.batchUpdateBindRecord(bindRecordList.subList(i, endIndex));
            i = endIndex;
        }
        return updateNum;
    }

    /**
     * 批量删除绑定关系
     *
     * @param parentNos 需要删除的绑定关系主键集合
     * @return 结果
     */
    @Override
    public int deleteBindRecordByParentNos(String[] parentNos) {
        return bindRecordMapper.deleteBindRecordByParentNos(parentNos);
    }

    /**
     * 删除绑定关系信息
     *
     * @param parentNo 绑定关系主键
     * @return 结果
     */
    @Override
    public int deleteBindRecordByParentNo(String parentNo) {
        return bindRecordMapper.deleteBindRecordByParentNo(parentNo);
    }

    /**
     * 绑定库位库存
     * @param inStockPutWayVo 上架对象
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public String bindStoreLocation(InStockPutWayVo inStockPutWayVo){
        logger.info("绑定库位：{}", inStockPutWayVo.toString());
        //添加绑定关系
        BindRecord bindRecord = new BindRecord();
        bindRecord.setParentNo(inStockPutWayVo.getShelfNo());
        bindRecord.setChildNo(inStockPutWayVo.getTrayNo());
        bindRecord.setBindType((long) BindTypeEnum.SHELF_TRAY.getCode());
        bindRecordService.insertBindRecord(bindRecord);
        //根据托盘判断是否已存在库存
        Tray tray=trayService.selectTrayByTrayNo(inStockPutWayVo.getTrayNo());
        if(tray==null){
            throw new RuntimeException( "托盘"+inStockPutWayVo.getTrayNo()+"不存在");
        }
        //获取托盘明细
        TrayDetail trayDetailQuery=new TrayDetail();
        trayDetailQuery.setTrayNo(inStockPutWayVo.getTrayNo());
        trayDetailQuery.setDelFlag("0");
        List<TrayDetail> trayDetails=trayDetailService.selectTrayDetailList(trayDetailQuery);
        if(trayDetails==null||trayDetails.size()==0){
            throw new RuntimeException("托盘"+inStockPutWayVo.getTrayNo()+"不存在明细数据");
        }
        String productNo=trayDetails.get(0).getProductNo();
        if(StringUtils.isNotEmpty(tray.getOutBillNo())){
            throw new RuntimeException("托盘"+inStockPutWayVo.getTrayNo()+"关联着出库单不能上架");
        }
        //根据料架判断收已经存在库存
        WmsStorehouseStock shelfQuery=new WmsStorehouseStock();
        shelfQuery.setContainerNo(inStockPutWayVo.getShelfNo());
        shelfQuery.setDelFlag("0");
        List<WmsStorehouseStock> shelfStocks=storehouseStockService.selectWmsStorehouseStockList(shelfQuery);
        if(shelfStocks!=null&&shelfStocks.size()>1){
            //判断绑定点位是否和当前库存点位一致
            if(!StrUtil.equalsIgnoreCase(shelfStocks.get(0).getStorehouseLocationNo(),inStockPutWayVo.getBinNo())){
                throw  new RuntimeException("料架"+ inStockPutWayVo.getShelfNo()+"存在库位"+shelfStocks.get(0).getStorehouseLocationNo());
            }
            String collect = shelfStocks.stream().map(WmsStorehouseStock::getStorehouseLocationNo).collect(Collectors.joining(", "));
            throw new RuntimeException( "料架"+ inStockPutWayVo.getShelfNo()+"存在多库位中"+collect);
        }
        //根据托盘判断是否已经存在库存
        WmsStorehouseStock trayQuery=new WmsStorehouseStock();
        trayQuery.setTrayNo(inStockPutWayVo.getTrayNo());
        trayQuery.setDelFlag("0");
        List<WmsStorehouseStock> trayStocks=storehouseStockService.selectWmsStorehouseStockList(trayQuery);
        if(trayStocks!=null&&trayStocks.size()!=0){
            throw new RuntimeException("托盘"+inStockPutWayVo.getTrayNo()+"存在库位"+shelfStocks.get(0).getStorehouseLocationNo());
        }
        //库位判断
        WmsStorehouseLocation location=locationService.selectWmsStorehouseLocationByNo(inStockPutWayVo.getBinNo());
        if(location==null){
            throw new RuntimeException("库位"+inStockPutWayVo.getBinNo()+"不存在");
        }
        if(!location.getLocationType().equals(StoreHouseLocationTypeEnum.IN_DOCKING_STATION.getCode())){
            throw new RuntimeException("库位"+inStockPutWayVo.getBinNo()+"不是入库类型");
        }
        WmsStorehouseArea houseArea=areaService.selectWmsStorehouseAreaByNo(location.getStorehouseAreaNo());
        if(houseArea==null){
            throw new RuntimeException( "库区"+location.getStorehouseAreaNo()+"不存在");
        }
        WmsStorehouseStock sourceStock=storehouseStockService.selectWmsStorehouseStockByLocationNo(location.getNo());
        if(sourceStock==null){
            throw new RuntimeException( "库位"+location.getNo()+"不存在库存数据");
        }
        if(!StorehouseStockStatusEnum.NORMAL.getCode().equals(sourceStock.getStatus())){
            throw new RuntimeException( "库位"+location.getNo()+"库存状态不是Normal");
        }

        WmsStorehouse storehouse=storehouseService.selectWmsStorehouseByNo(location.getStorehouseNo());
        if(storehouse==null){
            throw new RuntimeException("库位"+inStockPutWayVo.getBinNo()+"对应仓库不存在");
        }
        if(!storehouse.getTypeNo().equals(StoreHouseTypeEnum.LINE_PRODUCT.getCode())) {
            throw new RuntimeException( "仓库" + storehouse.getNo() + "不是线边仓");
        }
        //创建入库单
        InStockBill inStockBill=new InStockBill();
        inStockBill.setNo("IN"+TableNoUtil.getNo(InStockBill.class));
        WmsStorehouseLocation destLocation =emptyStockHelper.analyseInStock(inStockBill.getNo(),productNo,true,false);

        //生成入库单,todo 数据从哪里来，前端没有传
        inStockBill.setBillType(inStockPutWayVo.getBillType());
        inStockBill.setOrderStatus(InOrderStatusEnum.NEW.getCode());
        inStockBill.setRelOrderNo(tray.getErpInBillNo());
        inStockBill.setSourceLocation(location.getNo());
        inStockBill.setShelfNo(inStockPutWayVo.getShelfNo());
        inStockBill.setTrayNo(tray.getTrayNo());
        inStockBill.setDestLocation(destLocation.getNo());
        inStockBillService.insertInStockBill(inStockBill);
        //生成AGV任务 todo 此处库存还没绑定，货架和托盘号为什么从库存取
        agvTaskDispatchService.createTaskDispatch(inStockBill.getNo(),location, destLocation, AgvEnum.TASK_TYPE.IN,
                inStockPutWayVo.getShelfNo(),inStockPutWayVo.getTrayNo());
        logger.info("生成AGV成功：{}", inStockPutWayVo.toString());
        //托盘
        tray.setInBillNo(inStockBill.getNo());
        trayService.updateTray(tray);

        //创建入库单明细
        List<InStockBillDetail> inStockBillDetails=new ArrayList<>();
        for(TrayDetail item:trayDetails) {
            InStockBillDetail inStockBillDetail = new InStockBillDetail();
            inStockBillDetail.setNo(inStockBill.getNo());
            inStockBillDetail.setOrderNo(inStockBill.getNo());
            inStockBillDetail.setProductNo(item.getProductNo());
            inStockBillDetail.setProductName(item.getProductName());
            inStockBillDetail.setProductUnit(item.getProductUnit());
            inStockBillDetail.setQty(item.getQty());
            inStockBillDetail.setStatus(InOrderStatusEnum.NEW.getCode());
            inStockBillDetail.setBatchNo(item.getBatchNo());
            inStockBillDetails.add(inStockBillDetail);
        }
        inStockBillDetailService.batchInsertInStockBillDetail(inStockBillDetails);

        //绑定库存
        storehouseStockService.bindStorehouseStock(location,inStockPutWayVo.getShelfNo(),inStockPutWayVo.getTrayNo(),
                tray.getStockStatus(),tray.getInBillNo(), InOutStockTypeEnum.RECEIVING,
                InOutStorageOperationEnum.IN);
        logger.info("绑定库位成功：{}", inStockPutWayVo.toString());
        return "";

    }


}
